package news.controller.admin;
 
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
 
import javax.servlet.http.HttpServletRequest;

import jpa.BaseDao;
 
import net.vidageek.mirror.dsl.Mirror;
import net.vidageek.mirror.dsl.ClassController;
import net.vidageek.mirror.list.dsl.MirrorList;
import net.vidageek.mirror.reflect.dsl.AllReflectionHandler;
import net.vidageek.mirror.set.dsl.SetterHandler;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
 
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
 
public class CRUDController<T>{
    private BaseDao dao = null;
    private String modelName = "";
    private Class<?> clazz = null;
    private String[] columns = null;
    public void setDao(BaseDao<T> dao){
        this.dao = dao;
    }
    public void setModelClass(Class<?> cls){
        this.clazz = cls;
        this.modelName = cls.getName();
        setColumns(this.clazz.getDeclaredFields());
    }
    private void setColumns(Field[] fields){
        int cnt = 0;
        for (Field field : fields){
            if (!field.getName().startsWith("jdo")){
                cnt++;
            }
        }
        this.columns = new String[cnt];
        int i = 0;
        for (Field field : fields){
            if (field.getName().startsWith("jdo")){
                continue;
            }
            columns[i] = field.getName();
            i++;
        }
    }
    @RequestMapping(value="/add", method = RequestMethod.GET)
    public String getAddPage(ModelMap model) {
        model.addAttribute("name",  this.modelName);
        model.addAttribute("columns",  this.columns);
        return "add";
    }
 
    @RequestMapping(value="/add", method = RequestMethod.POST)
    public ModelAndView doAdd(T obj, HttpServletRequest request, ModelMap model) {
        this.dao.insert(obj);
        return new ModelAndView("redirect:list");
    }
 
    @RequestMapping(value="/update/{id}", method = RequestMethod.GET)
    public String getUpdatePage(@PathVariable String id, 
            HttpServletRequest request, ModelMap model) {
        model.addAttribute("obj",  this.dao.get(id));
        model.addAttribute("name",  this.modelName);
        model.addAttribute("columns",  this.columns);
        return "update";
 
    }
 
    @RequestMapping(value="/update", method = RequestMethod.POST)
    public ModelAndView doUpdate(T obj, String id, HttpServletRequest request, ModelMap model) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        T old = (T) this.dao.get(id);
        ClassController<T> cc = (ClassController<T>) new Mirror().on(this.clazz);
        AllReflectionHandler<T> arHandler = cc.reflectAll();
        MirrorList<Field> fields = arHandler.fields();
        SetterHandler setterHandler = new Mirror().on(old).set();
        
        for (String column : columns){
            if (column.toLowerCase().equals("id")){
                continue;
            }
            
            Object fieldValue = obj.getClass().getMethod("get" + column.substring(0, 1).toUpperCase() + column.substring(1)).invoke(obj);
            setterHandler.field(column).withValue(fieldValue);
        }
        this.dao.update(old);
        //return to list
        return new ModelAndView("redirect:list");
    }
 
    @RequestMapping(value="/delete/{id}", method = RequestMethod.GET)
    public ModelAndView delete(@PathVariable String id,
            HttpServletRequest request, ModelMap model) {
        T obj = (T) this.dao.get(id);
        if (obj != null){
            this.dao.delete(obj);
        }
        //return to list
        return new ModelAndView("redirect:../list");
 
    }
 
    //get all customers
    @RequestMapping(value="/list", method = RequestMethod.GET)
    public String list(ModelMap model) {
 
        List<T> list = this.dao.list();
 
        model.addAttribute("list",  list);
        model.addAttribute("name",  this.modelName);
        model.addAttribute("columns",  this.columns);
        return "list";
 
    }
}